package comRedis

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/go-redis/redis/v8"
	"github.com/jinzhu/copier"
)

// SetRedisString  向redis 存储字符串
func SetRedisString(prams *RedisPrams, value any) error {
	if prams.LockKey != "" && prams.LockValue != "" {
		success, err := prams.acquireLock()
		if err != nil {
			return err
		}
		if !success {
			return errors.New("获取锁失败")
		}
		defer func() {
			if prams.LockKey != "" && prams.LockValue != "" {
				released, err := prams.releaseLock()
				if err != nil {
					return
				}
				if !released {
					fmt.Println("释放锁失败")
					return
				}
			}
		}()
	}
	err := prams.Rdb.Set(prams.Ctx, prams.Key, value, prams.Expiration).Err()
	if err != nil {
		return err
	}
	return nil
}

// GetRedisString   向redis 获取字符串
func GetRedisString(prams *RedisPrams) (string, error) {

	if prams.LockKey != "" && prams.LockValue != "" {
		success, err := prams.acquireLock()
		if err != nil {
			return "", err
		}
		if !success {
			return "", errors.New("获取锁失败")
		}
		defer func() {
			if prams.LockKey != "" && prams.LockValue != "" {
				released, err := prams.releaseLock()
				if err != nil {
					return
				}
				if !released {
					fmt.Println("释放锁失败")
					return
				}
			}
		}()
	}
	// 检查键是否存在以及过期时间
	_, err := prams.Rdb.TTL(prams.Ctx, prams.Key).Result()
	if err != nil {
		fmt.Println("Error getting TTL:", err)
		return "", err
	}
	valueBytes, err := prams.Rdb.Get(prams.Ctx, prams.Key).Result()
	//err = json.Unmarshal(valueBytes, &data)
	if err != nil {
		return "", err
	}
	return valueBytes, nil
}

// SetRedisSlice  向redis 存储切片
func SetRedisSlice(prams *RedisPrams, value []any) error {
	if prams.LockKey != "" && prams.LockValue != "" {
		success, err := prams.acquireLock()
		if err != nil {
			return err
		}
		if !success {
			return errors.New("获取锁失败")
		}
		defer func() {
			if prams.LockKey != "" && prams.LockValue != "" {
				released, err := prams.releaseLock()
				if err != nil {
					return
				}
				if !released {
					fmt.Println("释放锁失败")
					return
				}
			}
		}()
	}
	valueJSON, err := json.Marshal(value)
	err = prams.Rdb.Set(prams.Ctx, prams.Key, valueJSON, prams.Expiration).Err()
	if err != nil {
		return err
	}
	return nil
}

// GetRedisSlice  向redis 获取切片
func GetRedisSlice[T any](prams *RedisPrams) ([]T, error) {
	var (
		data []T
	)
	if prams.LockKey != "" && prams.LockValue != "" {
		success, err := prams.acquireLock()
		if err != nil {
			return nil, err
		}
		if !success {
			return nil, errors.New("获取锁失败")
		}
		defer func() {
			if prams.LockKey != "" && prams.LockValue != "" {
				released, err := prams.releaseLock()
				if err != nil {
					return
				}
				if !released {
					fmt.Println("释放锁失败")
					return
				}
			}
		}()
	}
	// 检查键是否存在以及过期时间
	_, err := prams.Rdb.TTL(prams.Ctx, prams.Key).Result()
	if err != nil {
		fmt.Println("Error getting TTL:", err)
		return nil, err
	}
	valueBytes, err := prams.Rdb.Get(prams.Ctx, prams.Key).Bytes()
	err = json.Unmarshal(valueBytes, &data)
	if err != nil {
		return nil, err
	}
	return data, nil
}

// SetRedisHM  向redis 存储哈希结构(map)
func SetRedisHM(prams *RedisPrams, value interface{}) error {
	if prams.LockKey != "" && prams.LockValue != "" {
		success, err := prams.acquireLock()
		if err != nil {
			return err
		}
		if !success {
			return errors.New("获取锁失败")
		}
		defer func() {
			if prams.LockKey != "" && prams.LockValue != "" {
				released, err := prams.releaseLock()
				if err != nil {
					return
				}
				if !released {
					fmt.Println("释放锁失败")
					return
				}
			}
		}()
	}
	err := prams.Rdb.HMSet(prams.Ctx, prams.Key, value, prams.Expiration).Err()
	if err != nil {
		return err
	}
	return nil
}

// GetRedisHM  向redis 获取哈希结构(map)
func GetRedisHM(prams *RedisPrams) (map[string]interface{}, error) {
	var (
		data map[string]interface{}
	)
	if prams.LockKey != "" && prams.LockValue != "" {
		success, err := prams.acquireLock()
		if err != nil {
			return nil, err
		}
		if !success {
			return nil, errors.New("获取锁失败")
		}
		defer func() {
			if prams.LockKey != "" && prams.LockValue != "" {
				released, err := prams.releaseLock()
				if err != nil {
					return
				}
				if !released {
					fmt.Println("释放锁失败")
					return
				}
			}
		}()
	}
	// 检查键是否存在以及过期时间
	_, err := prams.Rdb.TTL(prams.Ctx, prams.Key).Result()
	if err != nil {
		fmt.Println("Error getting TTL:", err)
		return nil, err
	}
	vals, err := prams.Rdb.HGetAll(prams.Ctx, prams.Key).Result()
	if err != nil {
		return nil, err
	}
	err = copier.Copy(&data, vals)
	if err != nil {
		return nil, err
	}
	return data, nil
}

// SetRedisStruct  向redis 存储结构体
func SetRedisStruct(prams *RedisPrams, value interface{}) error {
	if prams.LockKey != "" && prams.LockValue != "" {
		success, err := prams.acquireLock()
		if err != nil {
			return err
		}
		if !success {
			return errors.New("获取锁失败")
		}
		defer func() {
			if prams.LockKey != "" && prams.LockValue != "" {
				released, err := prams.releaseLock()
				if err != nil {
					return
				}
				if !released {
					fmt.Println("释放锁失败")
					return
				}
			}
		}()
	}
	valueJSON, err := json.Marshal(value)
	err = prams.Rdb.Set(prams.Ctx, prams.Key, valueJSON, prams.Expiration).Err()
	if err != nil {
		return err
	}
	return nil
}

// GetRedisStruct  向redis 获取结构体
func GetRedisStruct[T any](prams *RedisPrams) (T, error) {
	var (
		data T
	)
	if prams.LockKey != "" && prams.LockValue != "" {
		success, err := prams.acquireLock()
		if err != nil {
			return data, err
		}
		if !success {
			return data, errors.New("获取锁失败")
		}
		defer func() {
			if prams.LockKey != "" && prams.LockValue != "" {
				released, err := prams.releaseLock()
				if err != nil {
					return
				}
				if !released {
					fmt.Println("释放锁失败")
					return
				}
			}
		}()
	}
	// 检查键是否存在以及过期时间
	_, err := prams.Rdb.TTL(prams.Ctx, prams.Key).Result()
	if err != nil {
		fmt.Println("Error getting TTL:", err)
		return data, err
	}
	valueBytes, err := prams.Rdb.Get(prams.Ctx, prams.Key).Bytes()
	if len(valueBytes) == 0 {
		return data, errors.New("没有获取到：" + prams.Key)
	}

	err = json.Unmarshal(valueBytes, &data)
	if err != nil {
		return data, err
	}
	return data, nil
}

// DellRedisKey  向redis 删除一个key
func DellRedisKey(prams *RedisPrams) error {
	if prams.LockKey != "" && prams.LockValue != "" {
		success, err := prams.acquireLock()
		if err != nil {
			return err
		}
		if !success {
			return errors.New("获取锁失败")
		}
		defer func() {
			if prams.LockKey != "" && prams.LockValue != "" {
				released, err := prams.releaseLock()
				if err != nil {
					return
				}
				if !released {
					fmt.Println("释放锁失败")
					return
				}
			}
		}()
	}
	err := prams.Rdb.Del(prams.Ctx, prams.Key).Err()
	if err != nil {
		fmt.Println(err)
		return errors.New("删除key失败")
	}
	return nil
}

// deleteKeysByPrefix 查询和删除以指定前缀开头的所有键
func deleteKeysByPrefix(prefix string, rdb *redis.Client) error {
	var cursor uint64
	ctx := context.Background()

	// 使用 SCAN 命令查找以 prefix 开头的键
	for {
		// SCAN 命令返回当前游标和匹配的键
		keys, nextCursor, err := rdb.Scan(ctx, cursor, prefix+"*", 0).Result()
		if err != nil {
			return err
		}

		// 批量删除找到的键
		if len(keys) > 0 {
			_, delErr := rdb.Del(ctx, keys...).Result()
			if delErr != nil {
				return delErr
			}
			fmt.Println("Deleted keys:", keys)
		}

		// 更新游标，继续扫描
		cursor = nextCursor

		// 如果游标为 0，说明遍历完所有键，跳出循环
		if cursor == 0 {
			break
		}
	}

	return nil
}

// getKeysByPrefix 使用 SCAN 命令查询以特定前缀开头的键
func getKeysByPrefix(prefix string, rdb *redis.Client) ([]string, error) {
	var keys []string
	var cursor uint64
	ctx := context.Background()

	// 使用 SCAN 命令查找以 prefix 开头的键
	for {
		// SCAN 命令返回当前游标和匹配的键
		result, nextCursor, err := rdb.Scan(ctx, cursor, prefix+"*", 0).Result()
		if err != nil {
			return nil, err
		}

		// 将结果追加到 keys 切片
		keys = append(keys, result...)
		cursor = nextCursor

		// 如果游标为 0，说明遍历完所有键，跳出循环
		if cursor == 0 {
			break
		}
	}

	return keys, nil
}
